#pragma once
#include <memory>
#include <mutex>
#include <pthread.h>
#include <unordered_map>

#include "CachePolicy.h"

namespace Cache
{

    //提前声明
    template<typename K,typename V> class LruCache;

    //创建缓存的数据结构(双向链表)
    template <typename K,typename V>
    class LruNode
    {
    private:
        K _key;
        V _value;
        std::weak_ptr<LruNode<K,V>> _prev;
        std::shared_ptr<LruNode<K,V>> _next;
    public:
        LruNode(K key,V value)
            :_key(key)
            ,_value(value)
            ,_next(nullptr)
        {}


        K getKey() const {return _key;};
        V getValue() const {return _value;};
        void setKey(const K& key) {_key = key;};
        void setValue(const V& value) {_value = value;};

        friend class LruCache<K,V>;
    };

    template <typename K,typename V>
    class LruCache : public CachePolicy<K,V>
    {
    public:
        using XLruNode = LruNode<K,V>;
        using LruNodePtr = std::shared_ptr<XLruNode>;
        using LruNodeMap = std::unordered_map<K,LruNodePtr>;


        LruCache(int size)
            :_capacity(size)
        {
            //初始化Lru内存
            InitLruCaches();
        }
        ~LruCache() override = default;

        //添加缓存
        void put(K key,V value) override
        {
            if (_capacity <= 0)
            {
                return;
            }

            std::lock_guard<std::mutex> lock(_mutex);
            auto it = _nodeMap.find(key);
            if (it != _nodeMap.end())//当前容器中存在key
            {
                UpDateLruCache(it->second,value);
                return;
            }
            AddLruCache(key,value);
        }

        //读取缓存,返回ture，则同时修改了缓存，返回false，那么该缓存没有修改
        bool get(K key, V& value) override
        {
            bool ret = false;
            std::lock_guard<std::mutex> lock(_mutex);
            auto it = _nodeMap.find(key);
            if (it != _nodeMap.end())//当前容器中存在key
            {
                moveToTail(it->second);
                value = it->second->getValue();
                ret = true;
            }
            return ret;
        }

        //删除缓存
        bool remove(K key,V& value) override
        {
            bool ret = false;
            std::lock_guard<std::mutex> lock(_mutex);
            auto it = _nodeMap.find(key);
            if (it != _nodeMap.end())
            {
                RemoveLruCache();
                ret = true;
            }
            return ret;
        }

    private:
        void InitLruCaches()
        {
            _head = std::make_shared<XLruNode>(K(),V());
            _tail = std::make_shared<XLruNode>(K(),V());
            _head->_next = _tail;
            _tail->_prev = _head;

        }

        void UpDateLruCache(LruNodePtr node,V& value)
        {
            //刷新数据
            node->setValue(value);
            //将刷新好的数据放到最新访问处
            moveToTail(node);
        }

        void AddLruCache(const K& key,const V& value)
        {
            if (_nodeMap.size() >= _capacity)//缓存已经满了
            {
                //删除掉最久没访问的数据
                RemoveLruCache();
            }
            //添加node到链表的最新处
            LruNodePtr node = std::make_shared<XLruNode>(key,value);
            addNode(node);
            //添加pair<key,value>到哈希表
            _nodeMap[key] = node;
        }

        void RemoveLruCache()
        {
            LruNodePtr node = _head->_next;
            removeNode(node);
            _nodeMap.erase(node->getKey());
        }

        void moveToTail(LruNodePtr node)
        {
            //删除当前链表位置的node
            removeNode(node);
            //添加链表
            addNode(node);
        }

        void addNode(LruNodePtr node)
        {
            node->_next = _tail;
            node->_prev = _tail->_prev;

            _tail->_prev.lock()->_next = node;
            _tail->_prev = node;

        }

        void removeNode(LruNodePtr node)
        {
            if (!node->_prev.expired() && node->_next)
            {
                auto prevNode = node->_prev.lock();
                prevNode->_next = node->_next;
                node->_next->_prev = prevNode;
                node->_next = nullptr;
            }
        }

        void addMap(const K& key,const V& value)
        {
            LruNodePtr node = std::make_shared<XLruNode>(key,value);
            _nodeMap.insert(std::make_pair(key,node));
        }

    private:
        int          _capacity;  //缓存容量
        LruNodeMap   _nodeMap;   //键值对，保存K->LruNodePtr
        LruNodePtr   _head;      //头指针（删除最久没访问的数据）
        LruNodePtr   _tail;      //尾指针(插入最新的数据)
        std::mutex   _mutex;     //多线程运行时候的锁
    };
} // Cache